package net.gdface.service.facelog;

import java.util.List;
import java.util.concurrent.TimeUnit;

import org.apache.commons.configuration2.CombinedConfiguration;

import com.facebook.swift.service.ThriftEventHandler;
import com.facebook.swift.service.ThriftServerConfig;
import com.facebook.swift.service.ThriftServerService;
import io.airlift.units.Duration;
import net.gdface.facelog.CommonConstant;
import net.gdface.facelog.FaceLogImpl;
import net.gdface.facelog.FacelogDecorator;
import net.gdface.facelog.GlobalConfig;
import net.gdface.facelog.IFaceLog;
import net.gdface.facelog.decorator.IFaceLogThriftDecorator;
import net.gdface.service.facelog.spring.RestfulService;

import static com.google.common.base.Preconditions.*;
import static net.gdface.service.facelog.ClientAddressProbeForNifty.NIFTY_ADDRESS_PROBE;
import static net.gdface.service.facelog.ClientAddressProbeForSpring.SPRING_ADDRESS_PROBE;

/**
 * {@link FaceLogImpl}服务封装
 * @author guyadong
 *
 */
public class FaceLogService extends ThriftServerService implements CommonConstant {
	/**
	 * {@link FaceLogImpl}单实例,不论是thritf服务还是spring boot服务,最终都调用此实例
	 */
	private static FaceLogImpl FACELOG_INSTANCE = new FaceLogImpl();
	private static FaceLogService service;
	private static FaceLogService httpService;
	/** 封装为thrift服务的facelog接口静态实例 */
	private static final IFaceLogThriftDecorator FACELOG_THRIFT_DECORATOR = 
			new IFaceLogThriftDecorator(FacelogDecorator.wrap(FACELOG_INSTANCE).registerClientAddressProbe(NIFTY_ADDRESS_PROBE).proxyInstance());
	/** 
	 * 用于Spring boot 的 facelog接口静态实例,
	 * 与{@link #FACELOG_THRIFT_DECORATOR}的不同在于使用不同的客户端地址侦听器
	 * 实例{@link net.gdface.facelog.FacelogDecorator.BaseClientAddressProbe} 
	 * */ 
	private static final IFaceLog FACELOG_SPRING_INSTANCE = 
			FacelogDecorator.wrap(FACELOG_INSTANCE).registerClientAddressProbe(SPRING_ADDRESS_PROBE).proxyInstance();
	/**
	 * 从配置文件中读取参数创建{@link ThriftServerConfig}实例
	 * @return 返回创建的{@link ThriftServerConfig}实例
	 */
	public static ThriftServerConfig makeThriftServerConfig(){
		ThriftServerConfig thriftServerConfig = new ThriftServerConfig();
		CombinedConfiguration config = GlobalConfig.getConfig();
		int intValue ;
		thriftServerConfig.setPort(config.getInt(SERVER_PORT,DEFAULT_PORT));
		if((intValue  = config.getInt(SERVER_CONNECTION_LIMIT,0)) >0){
			thriftServerConfig.setConnectionLimit(intValue);
		}
		if((intValue = config.getInt(SERVER_IDLE_CONNECTION_TIMEMOUT,0))>0){
			Duration timeout = new Duration(intValue,TimeUnit.SECONDS);
			thriftServerConfig.setIdleConnectionTimeout(timeout);
		}
		if((intValue = config.getInt(SERVER_WORKER_THREAD_COUNT,0))>0){
			thriftServerConfig.setWorkerThreads(intValue);
		}
		return thriftServerConfig;
	}
	/**
	 * 创建服务实例(frame,binary)
	 * @return 返回创建的服务实例
	 */
	public static synchronized final FaceLogService buildService(){
		return service = buildService(service,makeThriftServerConfig());
	}
	/**
	 * 创建HTTP服务实例(http,json)
	 * @return 返回创建的http服务实例
	 */
	public static synchronized final FaceLogService buildHttpService(){
		return httpService = buildService(httpService,
				makeThriftServerConfig()
					.setPort(GlobalConfig.getConfig().getInt(XHR_PORT, DEFAULT_PORT_XHR))
					.setIdleConnectionTimeout(Duration.valueOf("100ms"))
					.setTransportName(ThriftServerService.HTTP_TRANSPORT)
					.setProtocolName(ThriftServerService.JSON_PROTOCOL));
	}
	/**
	 * 启动RESTful WEB服务实例
	 */
	public static synchronized final void startRestfulService(){
		
		RestfulService.setHttpPort(GlobalConfig.getConfig().getInt(RESTFUL_PORT, DEFAULT_PORT_RESTFUL));
		RestfulService.setFacelogInstance(FACELOG_SPRING_INSTANCE);
		RestfulService.setSwaggerEnable(GlobalConfig.getConfig().getBoolean(RESTFUL_SWAGGER_ENABLE, true));
		RestfulService.setCorsEnable(GlobalConfig.getConfig().getBoolean(RESTFUL_CORS_ENABLE, true));
		RestfulService.run();
	}
	/**
	 * 创建服务实例<br>
	 * @param service 服务实例,如果为{@code null}或服务已经停止则创建新的服务实例
	 * @param config thrift服务配置
	 * @return 返回{@code service}或创建的新的服务实例
	 */
	private static FaceLogService buildService(FaceLogService service,ThriftServerConfig config){
		if(null == service || State.TERMINATED == service.state() || State.FAILED == service.state()){		
			service = ThriftServerService.bulider()
						.withServices(FACELOG_THRIFT_DECORATOR)	
						.setThriftServerConfig(config)
						.build(FaceLogService.class);	
		}
		checkState(State.NEW == service.state(),"INVALID service state %s ",service.toString());
		return service;
	}
	public FaceLogService(List<?> services, 
			List<ThriftEventHandler> eventHandlers,
			ThriftServerConfig thriftServerConfig) {
		super(services, eventHandlers, thriftServerConfig);
	}
	/**
	 * @return service
	 */
	public static FaceLogService getService() {
		return service;
	}
	/**
	 * @return httpService
	 */
	public static FaceLogService getHttpService() {
		return httpService;
	}
}
